package com.roncoo.education.common.pointcut;


import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import com.roncoo.education.common.core.base.Page;

import lombok.Data;
 
 
/**
* @author Promise
* @createTime 2018年12月18日 下午9:33:28
* @description 切面日志配置
*/
@Aspect
@Component
public class ObjectStoreInDB {
    
    private final static Logger log = org.slf4j.LoggerFactory.getLogger(ObjectStoreInDB.class);
    
	String minioDomain;
	String minioDbPlaceholder;
	
    @Autowired
    protected JdbcTemplate jdbcTemplate;        
    private ObjectStoreInDB setMinioInfo() {
    	String sql = "select config_key, config_value from os_system.sys_config where config_key in ('minioDomain', 'minioDbPlaceholder')";
    	
    	List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);

    	for (Map<String, Object> item : list) {
    		if ("minioDomain".equals(MapUtils.getString(item, "config_key"))) {
    			this.minioDomain = MapUtils.getString(item, "config_value");
    		}
    		if ("minioDbPlaceholder".equals(MapUtils.getString(item, "config_key"))) {
    			this.minioDbPlaceholder = MapUtils.getString(item, "config_value");
    		}    		
		}
    	
    	return this;
    }       
    
//    //表示匹配带有自定义注解的方法
//    @Pointcut("@annotation(com.web.springbootaoplog.config.Log)")
//    public void pointcut() {}    
//    @Pointcut("bean(*Dao)")
//    public void pointcutController() {}
    
    @Pointcut("execution(public * com.roncoo.education..dao.*Dao.getById(..)) ||"
    		+ "execution(public * com.roncoo.education..dao.*Dao.page*(..)) ||"
    		+ "execution(public * com.roncoo.education..dao.*Dao.list*(..))")
    public void pointcutOutDb() {}

	@Around("pointcutOutDb()")
    public Object pointcutOutDb(ProceedingJoinPoint point) {
        Object result = null;
        long beginTime = System.currentTimeMillis();        
    	
        try {
        	String className = point.getTarget().getClass().getSimpleName();
        	String methodName = ((MethodSignature) point.getSignature()).getMethod().getName();
            log.info("拦截到: " + className + "." + methodName);
            result = point.proceed();
            
            boolean execd = false;
            // 获取单对象
            if (result instanceof ObjectStoreBean && result != null) {
            	execd = true;
            	this.setMinioInfo().reploace(((ObjectStoreBean) result), minioDbPlaceholder, minioDomain);	
            }
            // 分页
            if (result instanceof Page && result != null && ((Page) result).getList() != null) {
            	execd = this.setMinioInfo().reploace(((Page) result).getList(), minioDbPlaceholder, minioDomain);
            }
            // 列表
            if (result instanceof List && result != null) {
            	execd = this.setMinioInfo().reploace((List) result, minioDbPlaceholder, minioDomain);
            }
            // 替换结果
            if (execd) {            	
            	long endTime = System.currentTimeMillis();
            	logForReplace("出库", point, minioDbPlaceholder, minioDomain, endTime - beginTime);
            }
        } catch (Throwable e) {
            // TODO Auto-generated catch block
        }
        return result;
    }
	
    @Pointcut("execution(public * com.roncoo.education..dao.*Dao.save(..)) ||"
    		+ "execution(public * com.roncoo.education..dao.*Dao.updateById(..))")
    public void pointcutInDb() {}
    
    @Around("pointcutInDb()")
    public Object pointcutInDb(ProceedingJoinPoint point) {
        Object result = null;
        long beginTime = System.currentTimeMillis();       
    	
        try {
        	String className = point.getTarget().getClass().getSimpleName();
        	String methodName = ((MethodSignature) point.getSignature()).getMethod().getName();
            log.info("拦截到: " + className + "." + methodName);
            Object[] args = point.getArgs();
            // 获取单对象
            boolean execd = false;
            if (args != null && args.length == 1 && args[0] instanceof ObjectStoreBean && args[0] != null) {
            	this.setMinioInfo().reploace(((ObjectStoreBean) args[0]), minioDomain, minioDbPlaceholder);
            	execd = true;
            }
            
            result = point.proceed();
            
            if (execd) {
            	long endTime = System.currentTimeMillis();
                logForReplace("入库", point, minioDomain, minioDbPlaceholder, endTime - beginTime);            	
            }
        } catch (Throwable e) {
            // TODO Auto-generated catch block
        }
        return result;
    }   
    
    private boolean reploace(List list, String from, String to) {
    	if (list != null && list.size() > 0 && list.get(0) instanceof ObjectStoreBean) {
    		for (Object item : list) {
    			reploace(((ObjectStoreBean) item), from, to);
			}
    		return true;
    	} 
    	return false;
    }
    
	private void reploace(ObjectStoreBean bean, String from, String to) {
		Class clazz = bean.getClass();
		Method[] methods = clazz.getMethods();
		for (Method method : methods) {
			String methodNameGet = method.getName();
			if (method.getReturnType() == String.class && methodNameGet.startsWith("get")) {				
				try {
					String value = (String) method.invoke(bean);

					if (value != null && value.length() >= from.length()) {
						String valueNew = value.replaceAll(from, to);						
						String methodNameSet = methodNameGet.replaceFirst("g", "s");
						Method methodSet = clazz.getMethod(methodNameSet, String.class);
						methodSet.invoke(bean, valueNew);
					}					
				} catch (Exception e) {
					e.printStackTrace();
				} 
			}
		}
	}
	
    private void logForReplace(String prefix, ProceedingJoinPoint point, String from, String to, long time) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        // 返回值
        String retType = method.getReturnType().getSimpleName();
        
        // 请求的类名
        String className = point.getTarget().getClass().getSimpleName();

        // 请求的方法名
        String methodName = signature.getName();
        // 请求的方法参数值
        List args = Arrays.asList(point.getArgs());
        List<String> argsClazz = new ArrayList<String>();
        for (Object arg : args) {
        	argsClazz.add(arg.getClass().getSimpleName());			
		}
        
        String argsStr = StringUtils.join(argsClazz.toArray(), " ,");
        log.info(prefix + "替换情况({} ——> {})：类名:{}, 方法:{}  {}({}), 耗时：{} ms", from, to, className, retType, methodName, argsStr, time);

    }
}